package jwcb.hire.common.security.service;


import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jwcb.hire.common.core.utils.ServletUtil;
import jwcb.hire.common.domain.constants.CacheConstants;
import jwcb.hire.common.domain.constants.SecurityConstants;
import jwcb.hire.common.domain.constants.TokenConstants;
import jwcb.hire.common.redis.RedisService.service.RedisService;
import jwcb.hire.common.domain.domain.dto.LoginUserDto;
import jwcb.hire.common.security.domain.dto.TokenDto;
import jwcb.hire.common.security.utils.JwtUtil;
import jwcb.hire.common.security.utils.SecurityUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * token服务类
 */
@Component
public class TokenService {


    /**
     * 登录用户过期时间(s)
     */
    private static final Long LOGIN_USER_EXP = CacheConstants.LOGIN_USER_EXPIRATION * 60 * 1000;
    @Autowired
    private RedisService redisService;
    /**
     * 创建token
     * @param loginUserDto 登录信息
     * @return token信息
     */
    public TokenDto createToken(LoginUserDto loginUserDto) {
        String userKey = UUID.randomUUID().toString().replaceAll("-", "");
        loginUserDto.setUserKey(userKey);
        refreshToken(loginUserDto);
        Map<String,Object> claimMap = new HashMap<>();
        claimMap.put(SecurityConstants.USER_KEY,userKey);
        claimMap.put(SecurityConstants.USER_ID,loginUserDto.getUserId());
        claimMap.put(SecurityConstants.USER_FROM,loginUserDto.getUserFrom());
        claimMap.put(SecurityConstants.USER_IDENTITY,loginUserDto.getUserIdentity());
        TokenDto tokenDto = new TokenDto();
        tokenDto.setAccessToken(JwtUtil.createToken(claimMap));
        tokenDto.setExpires(LOGIN_USER_EXP);
        refreshToken(loginUserDto);
        return tokenDto;
    }


    /**
     * 根据令牌获取用户信息
     * @param token 令牌
     * @return 用户信息
     */
    public LoginUserDto getLoginUserDto(String token) {
        LoginUserDto loginUserDto = null;
        // 解析令牌
        try {
            if(StringUtils.isNoneBlank(token)) {
                Claims claims = JwtUtil.parseToken(token);
                String userKey = JwtUtil.getUserKey(claims);
                String userId = JwtUtil.getUserId(claims);
                String userFrom = JwtUtil.getUserFrom(claims);
                loginUserDto = redisService.getCacheObject(getCacheKey(userKey,Long.valueOf(userId),userFrom), LoginUserDto.class);
            }
            return loginUserDto;
        }catch (Exception e) {}
        return loginUserDto;
    }

    /**
     * 通过请求信息获取用户信息
     * @param request 请求信息
     * @return 用户信息
     */
    public LoginUserDto getLoginUserDto(HttpServletRequest request) {
        String token = SecurityUtil.getToken(request);
        return getLoginUserDto(token);
    }


    /**
     * 获取用户信息
     * @return 用户信息
     */
    public LoginUserDto getLoginUserDto() {
        return getLoginUserDto(ServletUtil.getRequest());
    }


    /**
     * 删除用户登录状态
     */
    public void removeLoginStatus(String token) {
        if(StringUtils.isNoneBlank(token)) {
            Claims claims = JwtUtil.parseToken(token);
            String userKey = JwtUtil.getUserKey(claims);
            String userId = JwtUtil.getUserId(claims);
            String userFrom = JwtUtil.getUserFrom(claims);
            String cacheKey = getCacheKey(userKey,Long.valueOf(userId),userFrom);
            redisService.deleteObject(cacheKey);
        }
    }

    /**
     * 允许管理员删除别人的用户登录状态
     * @param userId 用户Id
     * @param userFrom 用户来源
     */
    public void removeLoginStatus(Long userId,String userFrom) {
        String split = TokenConstants.LOGIN_CACHE_INGO_SPLIT;
        String pattern = TokenConstants.LOGIN_TOKEN_KEY + split + userId + split +  userFrom +split + "*";
        redisService.scanAndDelete(pattern,100);
    }


    /**
     * 允许管理员设置用户登录状态
     * @param loginUserDto 用户信息
     */
    public void setLoginUser(LoginUserDto loginUserDto) {
        if(loginUserDto != null && StringUtils.isNoneBlank(loginUserDto.getUserKey())) {
            refreshToken(loginUserDto);
        }
    }
    /**
     * 延期令牌有效时间 不到120分钟,自动刷新
     * @param loginUserDto 用户数据
     */
    public void extendToken(LoginUserDto loginUserDto) {
        long expTime = loginUserDto.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if(currentTime - expTime <= CacheConstants.LOGIN_USER_EXP_CRITICAL_TIME * 60) {
            loginUserDto.setLoginTime(currentTime);
            loginUserDto.setExpireTime(currentTime + LOGIN_USER_EXP);
            refreshToken(loginUserDto);
        }
    }

    /**
     * 登录用户缓存
     * @param loginUserDto 登录用户信息
     */
    private void refreshToken(LoginUserDto loginUserDto) {
        loginUserDto.setLoginTime(System.currentTimeMillis());
        loginUserDto.setExpireTime(loginUserDto.getLoginTime() + LOGIN_USER_EXP);
        String cacheKey = getCacheKey(loginUserDto.getUserKey(), loginUserDto.getUserId(),loginUserDto.getUserFrom());
        redisService.setCacheObject(cacheKey,loginUserDto,LOGIN_USER_EXP, TimeUnit.MILLISECONDS);
    }


    /**
     * 获取缓存键
     * @param userKey 用户标识
     * @return 缓存键
     */
    public String getCacheKey(String userKey,Long userId,String userFrom) {
        String split = TokenConstants.LOGIN_CACHE_INGO_SPLIT;
        return TokenConstants.LOGIN_TOKEN_KEY + split + userId + split +  userFrom +split+ userKey;
    }

}
